package com.ruoyi.cost.controller;

import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

import com.ruoyi.cost.domain.AccSubject;
import com.ruoyi.cost.domain.AccVou;
import com.ruoyi.cost.domain.Balance;
import com.ruoyi.cost.service.IAccVouService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.cost.domain.AccAmount;
import com.ruoyi.cost.service.IAccAmountService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;

/**
 * 科目余额及发生额Controller
 *
 * @author 王志旸
 * @date 2024-07-09
 */
@RestController
@RequestMapping("/cost/amount")
public class AccAmountController extends BaseController {
    @Autowired
    private IAccAmountService accAmountService;

    @Autowired
    private IAccVouService accVouService;

    /**
     * 查询科目余额及发生额列表
     */
    @GetMapping("/list")
    public TableDataInfo list(AccAmount accAmount) {
        startPage();
        List<AccAmount> list = accAmountService.selectAccAmountList1(accAmount);
        return getDataTable(list);
    }

    @GetMapping("/list1")
    public TableDataInfo list1(String accMode, String accSubName) {
        List<AccAmount> list = accAmountService.selectAccAmountList(accMode, accSubName);
        Double j = 0.0;
        Double d = 0.0;
        List<AccAmount> accAmounts = new ArrayList<>();
        List<AccAmount> accAmount3 = accAmountService.getBeginCurr(accMode, accSubName);
        for (AccAmount accAmount2 : accAmount3) {
            if (accAmount2 != null) {
                accAmount2.setAccYear(accAmount2.getAccYear() + "年" + accAmount2.getAccPeriod() + "月");
                accAmount2.setAccPeriod("期初余额");
                accAmount2.setCreditLocalCurr("");
                accAmount2.setDebtorLocalCurr("");
                if (accAmount2.getStartLocalCurr().equals("")) {
                    accAmount2.setStartLocalCurr("0.0");
                }
                if (Double.parseDouble(accAmount2.getStartLocalCurr()) > 0) {
                    accAmount2.setEndBalance("借");
                } else if (Double.parseDouble(accAmount2.getStartLocalCurr()) == 0.00) {
                    accAmount2.setEndBalance("平");
                } else {
                    accAmount2.setEndBalance("贷");
                }
            } else {
                accAmount2 = new AccAmount();
                accAmount2.setAccPeriod("期初余额");
                accAmount2.setCreditLocalCurr("");
                accAmount2.setDebtorLocalCurr("");
                accAmount2.setEndBalance("平");
            }
            accAmount2.setEndLocalCurr(accAmount2.getStartLocalCurr());
            accAmounts.add(accAmount2);
        }

        for (AccAmount accAmount : list) {
            accAmount.setAccYear(accAmount.getAccYear() + "年" + accAmount.getAccPeriod() + "月");
            accAmount.setAccPeriod("本期合计");
            if (Double.parseDouble(accAmount.getDebtorLocalCurr()) > Double.parseDouble(accAmount.getCreditLocalCurr())) {
                accAmount.setEndBalance("借");
            } else if (Double.parseDouble(accAmount.getDebtorLocalCurr()) < Double.parseDouble(accAmount.getCreditLocalCurr())) {
                accAmount.setEndBalance("贷");
            } else {
                accAmount.setEndBalance("平");
            }
            j = Double.parseDouble(accAmount.getDebtorLocalCurr()) + j;
            d = Double.parseDouble(accAmount.getCreditLocalCurr()) + d;
            AccAmount accAmount1 = new AccAmount();
            accAmount1.setAccPeriod("本年合计");
            accAmount1.setAccYear(accAmount.getAccYear());
            accAmount1.setDebtorLocalCurr(String.format("%.2f", j));
            accAmount1.setCreditLocalCurr(String.format("%.2f", d));
            if (accAmount1.getDebtorLocalCurr().equals("0")) {
                accAmount1.setDebtorLocalCurr("0.0");
            }
            if (accAmount1.getCreditLocalCurr().equals("0")) {
                accAmount1.setCreditLocalCurr("0.0");
            }
            accAmounts.add(accAmount);
            accAmounts.add(accAmount1);
        }
        return getDataTable(mergeAccAmounts1(accAmounts));
    }

    public List<AccAmount> mergeAccAmounts1(List<AccAmount> accAmounts) {
        Map<String, AccAmount> mergedMap = new LinkedHashMap<>();

        for (AccAmount accAmount : accAmounts) {
            // 使用更具体的键值，如 "accYear-accPeriod"
            String key = accAmount.getAccYear() + "-" + accAmount.getAccPeriod();

            // 累加相同键的数据
            if (mergedMap.containsKey(key)) {
                AccAmount existing = mergedMap.get(key);
                double newDebtor = (existing.getDebtorLocalCurr() == null || existing.getDebtorLocalCurr().trim().isEmpty() ? 0.0 : Double.parseDouble(existing.getDebtorLocalCurr()))
                        + (accAmount.getDebtorLocalCurr() == null || accAmount.getDebtorLocalCurr().trim().isEmpty() ? 0.0 : Double.parseDouble(accAmount.getDebtorLocalCurr()));

                double newCredit = (existing.getCreditLocalCurr() == null || existing.getCreditLocalCurr().trim().isEmpty() ? 0.0 : Double.parseDouble(existing.getCreditLocalCurr()))
                        + (accAmount.getCreditLocalCurr() == null || accAmount.getCreditLocalCurr().trim().isEmpty() ? 0.0 : Double.parseDouble(accAmount.getCreditLocalCurr()));

                existing.setDebtorLocalCurr(String.format("%.2f", newDebtor));
                existing.setCreditLocalCurr(String.format("%.2f", newCredit));
            } else {
                // 如果是新键值，则直接放入
                mergedMap.put(key, accAmount);
            }
        }

        // 返回合并后的数据
        return new ArrayList<>(mergedMap.values());
    }


    @GetMapping("/listBalance")
    public TableDataInfo listBalance(String accMode) {
        startPage();
        List<Balance> list = accAmountService.listBalance(accMode);
        for (Balance map : list) {
            DecimalFormat df = new DecimalFormat("0.00");
            AccSubject vouSubType = accVouService.getVouSubType(map.getAccSubNum());
            map.setAccSubName(vouSubType.getAccSubName());
            AccAmount beginYearAmount = accAmountService.getBeginYearAmount(vouSubType.getAccSubNum(), accMode);
            AccAmount endYearAmount = accAmountService.getEndYearAmount(vouSubType.getAccSubNum(), accMode);
            map.setCreditLocalCurr(df.format(Double.parseDouble(map.getCreditLocalCurr())));
            map.setDebtorLocalCurr(df.format(Double.parseDouble(map.getDebtorLocalCurr())));
            map.setStartLocalCurr(df.format(Double.parseDouble(beginYearAmount.getStartLocalCurr())));
            map.setEndLocalCurr(df.format(Double.parseDouble(endYearAmount.getEndLocalCurr())));
            map.setDirection(beginYearAmount.getStartBalance());
        }
        return getDataTable(list);

    }


    @GetMapping("/listSupBalance0")
    public AjaxResult listSupBalance0(String accMode, String accSubName, String accBusiness) throws NoSuchFieldException, IllegalAccessException {
        if (accSubName == null) {
            return success(null);
        }
        if (accBusiness == null) {
            return success(null);
        }
        List<AccAmount> list = accAmountService.listSupBalance(accMode, accSubName);

        String[] split = accBusiness.split(",");
        if (split.length == 0){
            return success(null);
        }
        List<HashMap> map = accVouService.findSupsBySub(split, accMode, accSubName);
        List<AccAmount> accAmounts = new ArrayList<>();
        for (AccAmount accAmount : list) {
            Boolean flag = true;
            if (map.size() == 0) {
                return success(null);
            }
            for (HashMap hashMap : map) {
                String assisted_code = (String) hashMap.get("assisted_code");
                Field field = AccAmount.class.getDeclaredField("spare" + assisted_code);
                field.setAccessible(true); // 允许访问私有字段
                String spareValue = (String) field.get(accAmount);
                if (spareValue == null || spareValue.equals("")) {
                    flag = false;
                }
            }
            if (flag) {
                accAmounts.add(accAmount);
            }
        }
        List<Map<String, Object>> maps = listSupBalance(accMode, accSubName, split[0], accAmounts);

        for (Map<String, Object> vou : maps) {
            for (HashMap hashMap : map) {
                String assisted_code = (String) hashMap.get("assisted_code");
                String assisted_name = (String) hashMap.get("assisted_name");
                String spare = (String) vou.get("spare" + assisted_code);
                Map spareValue = accVouService.findSpareValue(spare, assisted_name, accMode);

                try {
                    vou.put(assisted_name, spareValue.get("custom_name"));
                } catch (Exception e) {
                    System.out.println(spare);
                }
            }
//            if (vou.get("acc_sub_num") != null && vou.get("accSubName") != null) {
//                vou.put("acc_sub_num",(String)vou.get("subCode")+vou.get("accSubName"));
//            }
        }
        List<AccAmount> accAmountList = new ArrayList<>();
        for (Map<String, Object> map1 : maps) {
            AccAmount accAmount = mapToObject(map1, AccAmount.class);
            accAmountList.add(accAmount);
        }
        HashMap<String, List<Map<String, Object>>> stringListHashMap = new HashMap<>();
        for (Map<String, Object> stringObjectMap : maps) {
            StringBuilder all = new StringBuilder();
            for (String s : split) {
                String spare1 = (String) stringObjectMap.get(s);
                all.append(spare1); // 使用 StringBuilder 提高拼接效率
            }
            String key = all.toString();
            // 如果分组不存在，则初始化
            stringListHashMap.computeIfAbsent(key, k -> new ArrayList<>());
            // 添加当前数据到对应分组
            stringListHashMap.get(key).add(stringObjectMap);
        }
        ArrayList<Map<String, Object>> objects = new ArrayList<>();
        for (List<Map<String, Object>> sumList : stringListHashMap.values()) {
            Double creditLocalCurrAll = 0.0;
            Double debtorLocalCurrAll = 0.0;
            Double startLocalCurrAll = 0.0;
            Double endLocalCurrAll = 0.0;
            Map<String, Object> objectObjectHashMap = new HashMap<>();
            for (Map<String, Object> stringObjectMap : sumList) {
                Double creditLocalCurr = Double.parseDouble((String) stringObjectMap.get("creditLocalCurr"));
                Double debtorLocalCurr = Double.parseDouble((String) stringObjectMap.get("debtorLocalCurr"));
                Double startLocalCurr = Double.parseDouble((String) stringObjectMap.get("startLocalCurr"));
                Double endLocalCurr = Double.parseDouble((String) stringObjectMap.get("endLocalCurr"));
                creditLocalCurrAll += creditLocalCurr;
                debtorLocalCurrAll += debtorLocalCurr;
                startLocalCurrAll += startLocalCurr;
                endLocalCurrAll += endLocalCurr;
                objectObjectHashMap = stringObjectMap;
            }
            objectObjectHashMap.put("creditLocalCurr", String.format("%.2f", creditLocalCurrAll));
            objectObjectHashMap.put("debtorLocalCurr", String.format("%.2f", debtorLocalCurrAll));
            objectObjectHashMap.put("startLocalCurr", String.format("%.2f", startLocalCurrAll));
            objectObjectHashMap.put("endLocalCurr", String.format("%.2f", endLocalCurrAll));
            objects.add(objectObjectHashMap);
        }


        return success(objects);
    }

    //    @GetMapping("/listSupBalance")
    public List<Map<String, Object>> listSupBalance(String accMode, String accSubName, String accBusiness, List<AccAmount> list) {
        if (accSubName == null || accSubName.equals("")) {
            return null;
        }
//        List<AccAmount> list = accAmountService.listSupBalance(accMode, accSubName);
        for (AccAmount map : list) {
            DecimalFormat df = new DecimalFormat("0.00");

            map.setCreditLocalCurr(df.format(Double.parseDouble(map.getCreditLocalCurr())));
            map.setDebtorLocalCurr(df.format(Double.parseDouble(map.getDebtorLocalCurr())));
//            map.setSupMap(getSpares(map.getAccSubNum(), accBusiness, map.getId(), accMode));
            map.setAccSubNum(map.getAccSubNum() + " " + map.getAccSubName());

        }
        List<AccAmount> accAmounts = new ArrayList<>();
        for (AccAmount accAmount : list) {
            accAmounts.add(accAmount);
        }
        accAmounts = list;
//        List<AccAmount> accAmounts1 = mergeAccAmounts(accAmounts);
        List<Map<String, Object>> listOfMaps = new ArrayList<>();

        for (AccAmount accVou : accAmounts) {
            Map<String, Object> map = new HashMap<>();
            // 使用反射获取所有字段
            Field[] fields = accVou.getClass().getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true); // 设置私有字段也可以访问
                try {
                    map.put(field.getName(), field.get(accVou)); // 将字段名和对应的值放入 map
                } catch (IllegalAccessException e) {
                    e.printStackTrace(); // 处理异常
                }
            }
            listOfMaps.add(map);
        }
        return listOfMaps;
    }

    public static <T> T mapToObject(Map<String, Object> map, Class<T> clazz) {
        try {
            // 创建目标对象实例
            T obj = clazz.getDeclaredConstructor().newInstance();

            // 获取所有字段
            Field[] fields = clazz.getDeclaredFields();

            for (Field field : fields) {
                field.setAccessible(true); // 设置私有字段可访问

                // 如果 Map 中存在字段名对应的值，则设置到对象中
                if (map.containsKey(field.getName())) {
                    Object value = map.get(field.getName());

                    // 检查类型匹配
                    if (value != null && field.getType().isAssignableFrom(value.getClass())) {
                        field.set(obj, value);
                    } else if (value != null) {
                        // 如果类型不匹配，尝试转换（例如基本类型包装类与原始类型间的转换）
                        field.set(obj, convertValue(field.getType(), value));
                    }
                }
            }

            return obj;

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Error while converting map to object");
        }
    }

    // 转换值类型的方法（可扩展支持更多类型）
    private static Object convertValue(Class<?> targetType, Object value) {
        if (targetType.isPrimitive()) {
            if (targetType == int.class) return ((Number) value).intValue();
            if (targetType == long.class) return ((Number) value).longValue();
            if (targetType == double.class) return ((Number) value).doubleValue();
            if (targetType == float.class) return ((Number) value).floatValue();
            if (targetType == boolean.class) return Boolean.parseBoolean(value.toString());
            if (targetType == char.class) return value.toString().charAt(0);
        }
        // 其他类型直接返回
        return targetType.cast(value);
    }

    @GetMapping("/listSupBalance2")
    public AjaxResult vouListSup3(String accMode, String accSubName, String accBusiness, String accBusiness1) throws Exception {
        List<AccAmount> list = accAmountService.listSupBalance(accMode, accSubName);
        String[] supList = accBusiness.split(",");
        String[] supSupList = accBusiness1.split(",");
        HashSet<String> stringHashSet = new HashSet<>();
        ArrayList<String> codeList = new ArrayList<>();
        HashMap<String, String> objectObjectHashMap = new HashMap<>();
        List<HashMap> map = null;
        List<HashMap> map1 = null;
        if (supList.length > 1) {
            map = accVouService.findSups(supList, accMode);
            map1 = accVouService.findSupsLoc(supList, accMode, supSupList);

        } else if (supList.length <= 0) {
            return success(null);
        } else {
            map = accVouService.findSupsOne(supList, accMode);
            map1 = accVouService.findSupsLocOne(supList, accMode, supSupList);
        }
        for (HashMap hashMap : map) {
            stringHashSet.add((String) hashMap.get("subject_code"));
            codeList.add((String) hashMap.get("assisted_code"));
            String assisted_name = (String) hashMap.get("assisted_name");
            String assisted_code = (String) hashMap.get("assisted_code");
            objectObjectHashMap.put(assisted_name, assisted_code);
        }
        List<AccAmount> vouList = list.stream()
                .filter(obj -> stringHashSet.contains(obj.getAccSubNum()))
                .collect(Collectors.toList());
        for (HashMap hashMap : map) {
            String assisted_name = (String) hashMap.get("assisted_name");
            for (HashMap hashMap1 : map1) {
                String custom_name = (String) hashMap1.get("custom_name");
                if (assisted_name.equals(custom_name)) {
                    hashMap.put("code", (String) hashMap1.get("name"));
                }
            }
        }
        List<AccAmount> matchedList = new ArrayList<>();
        for (AccAmount accVou : vouList) {
            boolean allMatch = true; // 初始化为true，表示当前对象假定所有条件匹配
            for (HashMap<String, Object> hashMap : map) {
                String assisted_name = (String) hashMap.get("assisted_name");
                String assisted_code = (String) hashMap.get("assisted_code");

                Field field = AccAmount.class.getDeclaredField("spare" + assisted_code);
                field.setAccessible(true); // 允许访问私有字段
                String spareValue = (String) field.get(accVou);

                if (!spareValue.equals(hashMap.get("code"))) {
                    allMatch = false; // 有一个不匹配则标志置为false
                    break; // 退出当前内层循环
                }
            }

            if (allMatch) {
                matchedList.add(accVou); // 如果所有条件都匹配，将该对象添加到新的列表中
            }
        }
        List list1 = listSupBalance2(accMode, matchedList, null, supSupList[0], supList[0]);
        return success(list1);


    }


    //    @PreAuthorize("@ss.hasPermi('cost:amount:list')")
//    @GetMapping("/listSupBalance2")
    public List<AccAmount> listSupBalance2(String accMode, List<AccAmount> list, String accSubName, String accBusiness1, String accBusiness) {
        accSubName = null;
//        List<AccAmount> list = accAmountService.listSupBalance(accMode, accSubName);
        for (AccAmount map : list) {
            DecimalFormat df = new DecimalFormat("0.00");
//            AccSubject vouSubType = accVouSer vice.getVouSubType(map.getAccSubNum());
//            map.setAccSubName(vouSubType.getAccSubName());
//            AccAmount beginYearAmount = accAmountService.getBeginYearAmount(vouSubType.getAccSubNum(),accMode);
//            AccAmount endYearAmount = accAmountService.getEndYearAmount(vouSubType.getAccSubNum(),accMode);
            map.setCreditLocalCurr(df.format(Double.parseDouble(map.getCreditLocalCurr())));
            map.setDebtorLocalCurr(df.format(Double.parseDouble(map.getDebtorLocalCurr())));
//            map.setSupMap(getSpares(map.getAccSubNum(), accBusiness, map.getId(), accMode));
            map.setAccSubNum(map.getAccSubNum() + " " + map.getAccSubName());

        }
        List<AccAmount> accAmounts = new ArrayList<>();
        for (AccAmount accAmount : list) {
            accAmounts.add(accAmount);
        }
        List<AccAmount> accAmounts1 = mergeAccAmounts2(accAmounts);
        return accAmounts1;
    }

    public static List<AccAmount> mergeAccAmounts2(List<AccAmount> accAmountList) {
        Map<String, AccAmount> mergedMap = new HashMap<>();

        for (AccAmount acc : accAmountList) {
            // 使用 getSupMap() 获取 supMap
            String supMap = acc.getAccSubNum();

            // 如果 Map 中已存在该 supMap，则累加字段，否则存入 Map
            mergedMap.merge(supMap, acc, (existing, newAcc) -> {
                existing.add(newAcc);
                return existing;
            });
        }

        // 将 Map 的值转换为 List 返回
        return new ArrayList<>(mergedMap.values());
    }


    public static List<AccAmount> mergeAccAmounts(List<AccAmount> accAmountList) {
        Map<String, AccAmount> mergedMap = new HashMap<>();

        for (AccAmount acc : accAmountList) {
            // 使用 getSupMap() 获取 supMap
            String supMap = acc.getSupMap();

            // 如果 Map 中已存在该 supMap，则累加字段，否则存入 Map
            mergedMap.merge(supMap, acc, (existing, newAcc) -> {
                existing.add(newAcc);
                return existing;
            });
        }

        // 将 Map 的值转换为 List 返回
        return new ArrayList<>(mergedMap.values());
    }

    public String getSpares(String accSubNum, String accBusiness, String id, String accMode) {
        Map subAssistedAcc = accAmountService.getSubAssistedAcc(accSubNum, accBusiness, accMode);
        HashMap<String, String> map = new HashMap<>();
        if (subAssistedAcc != null) {
            String assisted_code = subAssistedAcc.get("assisted_code").toString();
            String spare = "spare";
            spare = spare + assisted_code;
            String supName = accAmountService.getSupSpares(accSubNum, accBusiness, id, accMode, spare);
            map.put(accBusiness, supName);
            return supName;
        }
        return "";
    }


    /**
     * 导出科目余额及发生额列表
     */
//    @PreAuthorize("@ss.hasPermi('cost:amount:export')")
    @Log(title = "科目余额及发生额", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, AccAmount accAmount) {
        List<AccAmount> list = accAmountService.selectAccAmountList1(accAmount);
        ExcelUtil<AccAmount> util = new ExcelUtil<AccAmount>(AccAmount.class);
        util.exportExcel(response, list, "科目余额及发生额数据");
    }

    /**
     * 获取科目余额及发生额详细信息
     */
//    @PreAuthorize("@ss.hasPermi('cost:amount:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") String id) {
        return success(accAmountService.selectAccAmountById(id));
    }

    /**
     * 新增科目余额及发生额
     */
//    @PreAuthorize("@ss.hasPermi('cost:amount:add')")
    @Log(title = "科目余额及发生额", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody AccAmount accAmount) {
        return toAjax(accAmountService.insertAccAmount(accAmount));
    }

    /**
     * 修改科目余额及发生额
     */
//    @PreAuthorize("@ss.hasPermi('cost:amount:edit')")
    @Log(title = "科目余额及发生额", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody AccAmount accAmount) {
        return toAjax(accAmountService.updateAccAmount(accAmount));
    }

    /**
     * 删除科目余额及发生额
     */
//    @PreAuthorize("@ss.hasPermi('cost:amount:remove')")
    @Log(title = "科目余额及发生额", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable String[] ids) {
        return toAjax(accAmountService.deleteAccAmountByIds(ids));
    }
}
